package com.yj.rselasticsearch.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yj.common.config.RuoYiConfig;
import com.yj.common.constant.DataConstants;
import com.yj.common.constant.DataScopeConstants;
import com.yj.common.constant.HttpStatus;
import com.yj.common.core.domain.AjaxResult;
import com.yj.common.core.domain.entity.*;
import com.yj.common.core.domain.model.LoginUser;
import com.yj.common.exception.ServiceException;
import com.yj.common.utils.DateUtils;
import com.yj.common.utils.FastUtils;
import com.yj.common.utils.SecurityUtils;
import com.yj.common.utils.StringUtils;
import com.yj.common.utils.file.FileUploadUtils;
import com.yj.rselasticsearch.domain.dto.FileInfoDto;
import com.yj.rselasticsearch.domain.vo.MemberVo;
import com.yj.rselasticsearch.service.*;
import com.yj.system.domain.SysRoleDept;
import com.yj.system.mapper.SysRoleDeptMapper;
import com.yj.system.service.ISysDeptService;
import com.yj.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import com.yj.rselasticsearch.mapper.FileInfoMapper;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class FileInfoServiceImpl extends ServiceImpl<FileInfoMapper, FileInfo> implements FileInfoService {
    @Resource
    private FileTypeService fileTypeService;

    @Resource
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Resource
    private TagInfoService tagInfoService;

    @Autowired
    @Qualifier("restHighLevelClient")
    private RestHighLevelClient client;

    @Resource
    private FileInfoMapper fileInfoMapper;

    @Resource
    private ISysDeptService deptService;


    @Resource
    private TokenService tokenService;

    @Resource
    private ISysUserService sysUserService;

    @Resource
    private SysRoleDeptMapper deptMapper;

    @Resource
    private FileUploadLogService fileUploadLogService;

    @Resource
    private FileOptionLogService fileOptionLogService;

    /**
     * 上传文件并进行文件内容识别上传到es
     *
     * @return
     */
    @Override
    public void uploadFileInfo(FileInfo fileInfos) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        String.format("当前登录用户为：%s", loginUser.getUsername());
        FileInfoUploadThread fileUploadThread = new FileInfoUploadThread(fileInfos, fileUploadLogService, fileTypeService, tagInfoService, this, elasticsearchRestTemplate, fileInfoMapper, client, loginUser, fileOptionLogService);
        fileUploadThread.run();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult deleteFileInfoById(Integer id) {
        try {
            String userName = SecurityUtils.getLoginUser().getUsername();
            //先删除数据库存储的文档信息
            FileInfo fileInfo = fileInfoMapper.selectById(id);
            fileInfo.setStatus(1);
            fileInfo.setUpdateBy(userName);
            int result = fileInfoMapper.updateById(fileInfo);
            if (result > 0) {
                BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                        .should(QueryBuilders.matchBoolPrefixQuery("id", id));
                Query query = new NativeSearchQuery(boolQueryBuilder);
                elasticsearchRestTemplate.delete(query, FileInfo.class);
            }
            return AjaxResult.success();
        } catch (Exception e) {
            log.info(e.getMessage());
            e.printStackTrace();
            return AjaxResult.error("系统内部错误");
        }

    }

    @Override
    public AjaxResult fileUpload(MultipartFile file) {
        try {
            // 上传文件路径
            String filePath = RuoYiConfig.getUploadPath() + "/fileInfo";
            // 上传并返回新文件名称
            String fileName = FileUploadUtils.upload(filePath, file);
            return AjaxResult.success(fileName);
        } catch (Exception ex) {
            throw new ServiceException(ex.getMessage());
        }

    }

    @Override
    public AjaxResult selectOne(Integer id) {
        //分页
        //需要查询的字段，根据输入的内容分词全文检索fileName和content字段
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                .should(QueryBuilders.matchBoolPrefixQuery("id", id));
        //构建高亮查询
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(boolQueryBuilder)
                .build();
        //查询
        SearchHits<FileInfo> search = null;
        try {
            search = elasticsearchRestTemplate.search(searchQuery, FileInfo.class);
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new ServiceException(String.format("操作错误，请联系管理员！%s", ex.getMessage()));
        }
        //设置一个最后需要返回的实体类集合
        List<FileInfo> resultList = new LinkedList<>();
        //遍历返回的内容进行处理
        for (org.springframework.data.elasticsearch.core.SearchHit<FileInfo> searchHit : search.getSearchHits()) {
            //高亮的内容
            Map<String, List<String>> highlightFields = searchHit.getHighlightFields();
            //将高亮的内容填充到content中
            searchHit.getContent().setFileName(highlightFields.get("fileName") == null ? searchHit.getContent().getFileName() : highlightFields.get("fileName").get(0));
            searchHit.getContent().setContent(highlightFields.get("content") == null ? searchHit.getContent().getContent() : highlightFields.get("content").get(0));
            resultList.add(searchHit.getContent());
        }
        return AjaxResult.success(resultList.get(DataConstants.Number.ZERO));
    }

    @Override
    public AjaxResult pageSearchFileInfo(FileInfoDto fileInfo, HttpServletRequest request) {
        //获取当前用户权限
        LoginUser loginUser = null;
        MemberVo user = null;
        SysUser sysUser = null;
        if (FastUtils.checkNull(request)) {
            loginUser = SecurityUtils.getLoginUser();
            sysUser = loginUser.getUser();
        } else {
            user = (MemberVo) tokenService.getLoginUser(request);
            if (FastUtils.checkNull(user)) {
                throw new ServiceException("未获取到登录信息，请登录！", HttpStatus.UNAUTHORIZED);
            }
            sysUser = sysUserService.selectUserAuthByPhone(user.getPhone());
        }
        IPage<FileInfo> fileInfoPage = new Page<>(fileInfo.getPageIndex(), fileInfo.getPageSize());
        if (fileInfo.getEndTime() != null) {
            fileInfo.setEndTime(DateUtils.addDays(fileInfo.getEndTime(), 1));
        }
        if (!FastUtils.checkNull(user)) {
            //小程序访问得时候数据过滤
            if (!FastUtils.checkNull(fileInfo.getDeptId()) && !FastUtils.checkNull(fileInfo.getFileTypeId())) {
                fileInfo.setIsOpen(DataConstants.Number.ZERO);
            }
        }
        List<FileInfo> fileInfoList = list(new LambdaQueryWrapper<FileInfo>()
                .like(!StringUtils.isEmpty(fileInfo.getFileName()), FileInfo::getFileName, fileInfo.getFileName())
                .ge(fileInfo.getBeginTime() != null, FileInfo::getCreateTime, fileInfo.getBeginTime())
                .lt(fileInfo.getEndTime() != null, FileInfo::getCreateTime, fileInfo.getEndTime())
                .eq(fileInfo.getFileTypeId() != null, FileInfo::getFileTypeId, fileInfo.getFileTypeId())
                .eq(fileInfo.getDeptId() != null, FileInfo::getDeptId, fileInfo.getDeptId())
                .eq(fileInfo.getIsOpen() != null, FileInfo::getIsOpen, fileInfo.getIsOpen())
                .eq(FileInfo::getStatus, DataConstants.Number.ZERO)
                .orderByDesc(FileInfo::getUpdateTime));

        List<FileInfo> fileInfoList1 = new ArrayList<>();
        if (!FastUtils.checkNull(sysUser) && !sysUser.isAdmin()) {
            List<SysRoleDept> sysRoleDepts = null;
            List<SysRoleFileType> sysRoleFileTypes = null;
            String dataScope = null;
            if (FastUtils.checkNull(user)) {
                sysRoleDepts = fileTypeService.getRoleDepts(null).getSysRoleDepts();
                sysRoleFileTypes = fileTypeService.getRoleDepts(null).getFileTypes();
                dataScope = fileTypeService.getRoleDepts(null).getDataScope();
            } else {
                sysRoleDepts = fileTypeService.getRoleDepts(sysUser).getSysRoleDepts();
                sysRoleFileTypes = fileTypeService.getRoleDepts(sysUser).getFileTypes();
                dataScope = fileTypeService.getRoleDepts(sysUser).getDataScope();
            }
            //数据过滤
            List<FileInfo> fileInfos = new ArrayList<>();

            if (!DataScopeConstants.DATASCOPE.DATA_SCOPE_SELF.equals(dataScope) && !DataScopeConstants.DATASCOPE.DATA_SCOPE_ALL.equals(dataScope)) {
                for (FileInfo fileInfo1 : fileInfoList) {
                    if (FastUtils.checkNull(fileInfo.getFileTypeId()) && FastUtils.checkNull(fileInfo.getDeptId())) {
                        if (fileInfo1.getIsOpen().equals(DataConstants.Number.ZERO)) {
                            fileInfos.add(fileInfo1);
                            continue;
                        }
                    }
                    if (!FastUtils.checkNullOrEmpty(sysRoleDepts)) {
                        for (SysRoleDept sysRoleDept : sysRoleDepts) {
                            if (!FastUtils.checkNull(fileInfo.getDeptId())) {
                                //公开文档类型
                                if (fileInfo1.getDeptId().toString().equals(fileInfo.getDeptId().toString()) && fileInfo1.getIsOpen().equals(DataConstants.Number.ZERO)) {
                                    fileInfos.add(fileInfo1);
                                    break;
                                }
                            } else if (!FastUtils.checkNull(fileInfo.getFileTypeId()) && !FastUtils.checkNull(fileInfo.getDeptId())) {
                                //分类查询，只要是这分类得都算
                                if (fileInfo1.getDeptId().toString().equals(sysRoleDept.getDeptId().toString())) {
                                    fileInfos.add(fileInfo1);
                                    break;
                                }
                            } else {
                                //所有
                                if (fileInfo1.getDeptId().toString().equals(sysRoleDept.getDeptId().toString()) || fileInfo1.getIsOpen().equals(DataConstants.Number.ZERO)) {
                                    fileInfos.add(fileInfo1);
                                    break;
                                }
                            }
                        }
                    }
                }
            } else if (DataScopeConstants.DATASCOPE.DATA_SCOPE_SELF.equals(dataScope)) {
                for (FileInfo fileInfos2 : fileInfoList) {
                    if (!FastUtils.checkNull(fileInfo.getDeptId())) {
                        //公开文档类型
                        if (fileInfos2.getDeptId().toString().equals(fileInfo.getDeptId().toString()) && fileInfos2.getIsOpen().equals(DataConstants.Number.ZERO)) {
                            fileInfos.add(fileInfos2);
                        }
                    } else if (!FastUtils.checkNull(fileInfo.getFileTypeId()) && FastUtils.checkNull(fileInfo.getDeptId())) {
                        //分类查询，只要是这分类得都算
                        if (fileInfos2.getIsOpen().toString().equals(DataConstants.Number.ZERO.toString())) {
                            fileInfos.add(fileInfos2);
                        } else {
                            if (fileInfos2.getCreateBy().equals(sysUser.getUserName())) {
                                fileInfos.add(fileInfos2);
                            }
                        }
                    } else {
                        if (fileInfos2.getIsOpen().toString().equals(DataConstants.Number.ZERO.toString())) {
                            fileInfos.add(fileInfos2);
                        } else {
                            if (fileInfos2.getCreateBy().equals(sysUser.getUserName())) {
                                fileInfos.add(fileInfos2);
                            }
                        }
                    }
                }
            } else {
                for (FileInfo fileInfo1 : fileInfoList) {
                    if (!FastUtils.checkNull(fileInfo.getDeptId()) && FastUtils.checkNull(fileInfo.getFileTypeId())) {
                        //公开文档类型
                        if (fileInfo.getDeptId().toString().equals(fileInfo1.getDeptId().toString()) && fileInfo1.getIsOpen().equals(DataConstants.Number.ZERO)) {
                            fileInfos.add(fileInfo1);
                        }
                    } else if (!FastUtils.checkNull(fileInfo.getFileTypeId()) && !FastUtils.checkNull(fileInfo.getDeptId())) {
                        //分类查询，只要是这分类得都算
                        if (fileInfo.getFileTypeId().toString().equals(fileInfo1.getFileTypeId().toString())) {
                            fileInfos.add(fileInfo1);
                        }
                    } else {
                        fileInfos.add(fileInfo1);
                        continue;
                    }
                }
            }
            //文件类型编辑权限过滤
            for (FileInfo infos1 : fileInfos) {
                if (!FastUtils.checkNullOrEmpty(sysRoleDepts)) {
                    for (SysRoleDept sysRoleDept : sysRoleDepts) {
                        if (sysRoleDept.getDeptId().toString().equals(infos1.getDeptId().toString())) {
                            if (!FastUtils.checkNullOrEmpty(sysRoleFileTypes)) {
                                for (SysRoleFileType sysRoleFileType : sysRoleFileTypes) {
                                    if (infos1.getFileTypeId().toString().equals(sysRoleFileType.getFileTypeId().toString())) {
                                        infos1.setIsEdit(DataConstants.Is.YES_INT);
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            //文件类型过滤
            if (FastUtils.checkNull(fileInfo.getDeptId())) {
                for (FileInfo info : fileInfos) {
                    if (!FastUtils.checkNullOrEmpty(sysRoleFileTypes)) {
                        for (SysRoleFileType sysRoleFileType : sysRoleFileTypes) {
                            if (info.getIsOpen().equals(DataConstants.Number.ONE)) {
                                //非公开
                                if (info.getFileTypeId().toString().equals(sysRoleFileType.getFileTypeId().toString())) {
                                    fileInfoList1.add(info);
                                    break;
                                }
                            } else {
                                //公开
                                fileInfoList1.add(info);
                                break;
                            }
                        }
                    } else {
                        if (info.getIsOpen().toString().equals(DataConstants.Number.ZERO.toString())) {
                            //公开
                            fileInfoList1.add(info);
                        }
                    }
                }
            } else {
                fileInfoList1.addAll(fileInfos);
            }
        } else {
            fileInfoList1 = fileInfoList;
            fileInfoList1.forEach(data -> {
                data.setIsEdit(DataConstants.Is.YES_INT);
            });
        }
        fileInfoList1.forEach(data -> {
            SysDept sysDept = deptService.selectDeptById(data.getDeptId().longValue());
            SysUser sysUser1 = sysUserService.selectUserByUserName(data.getCreateBy());
            data.setCreateName(sysUser1.getNickName());
            data.setDeptName(sysDept.getDeptName());
        });
        //分页信息
        fileInfoPage.setTotal(fileInfoList1.size());
        fileInfoPage.setCurrent(fileInfo.getPageIndex());
        fileInfoPage.setSize(fileInfo.getPageSize());
        fileInfoPage.setPages(fileInfoPage.getTotal() % fileInfo.getPageSize());
        int fromIndex = ((int) fileInfoPage.getCurrent() - 1) * (int) fileInfoPage.getSize(); //第几行数据开始
        int toIndex = fromIndex + (int) fileInfoPage.getSize(); //第几行结束
        if (toIndex > (int) fileInfoPage.getTotal()) {
            toIndex = (int) fileInfoPage.getTotal();
        }
        List<FileInfo> pageList = fileInfoList1.subList(fromIndex, toIndex);
        fileInfoPage.setRecords(pageList);
        return AjaxResult.success(fileInfoPage);
    }

    /**
     * 更新文件内容信息
     *
     * @return
     */
    @Override

    public void updateByFileInfoId(FileInfo fileInfos) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        log.info(String.format("当前登录用户为：%s", loginUser.getUsername()));
        FileUploadThread fileUploadThread = new FileUploadThread(fileInfos, fileUploadLogService, fileTypeService, tagInfoService, this, elasticsearchRestTemplate, fileInfoMapper, client, loginUser, fileOptionLogService);
        fileUploadThread.run();
    }

    /**
     * 文件转base64
     *
     * @param file
     * @return
     * @throws IOException
     */
    private byte[] getContent(File file) throws IOException {

        long fileSize = file.length();
        if (fileSize > Integer.MAX_VALUE) {
            log.info("file too big...");
            return null;
        }
        FileInputStream fi = new FileInputStream(file);
        byte[] buffer = new byte[(int) fileSize];
        int offset = 0;
        int numRead = 0;
        while (offset < buffer.length
                && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) {
            offset += numRead;
        }
        // 确保所有数据均被读取
        if (offset != buffer.length) {
            throw new ServiceException("Could not completely read file "
                    + file.getName());
        }
        fi.close();
        return buffer;
    }
}
